-module(ac_80211_server).
-include("protocol.hrl").
-hehaviour(gen_server).
-define(SERVER,?MODULE).
-export([start/0,start_link/0,start_link/1,init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
-export([handle/2,do/2]).

handle(Pid,Request) ->
	gen_server:cast(Pid,Request).
do(Pid,report)->
	io:format("dump counter ~p~n",[gen_server:call(Pid,report)]).
	
start()  ->
	gen_server:start({local, ?SERVER}, ?MODULE, [], []).
start_link(IP) ->
	<<IP1,IP2,IP3,IP4>> = IP,
	Title = io_lib:format("AC-~w.~w.~w.~w",[IP1,IP2,IP3,IP4]),
	gen_event:notify(sys_mon_evt,{up,{self(),list_to_binary(Title),ac}}),
	gen_server:start_link(?MODULE, [IP], []).
	
start_link() ->
	start_link(undefined).
	
init([IP]) ->
	error_logger:info_msg("ac server ~w start...",[IP]),
	process_flag(trap_exit, true),
	{ok,{running,IP,#wlan80211c{}}}.
	
handle_call(report,_,{running,IP,Counter}) ->
	{reply,{IP,Counter},{running,IP,Counter}};
	
handle_call(Cmd,_,State) ->
	{reply, {error,io_lib:format("no func ~w define in ~s ~n",[Cmd,?MODULE])}, State}.
	
handle_cast({packet_comming,P_Tuple},{running,IP,Counter}) ->
	{Sub_Mac,Sub_Packet} = parse80211frame(P_Tuple#packet_tuple.packet),
	[#lwapp_protocol{ap=AP_ip}|_] = P_Tuple#packet_tuple.context,	%% get lwapp value
	#l1_protocol{index=Packet_Index} = lists:last(P_Tuple#packet_tuple.context),
	sub_dispatcher:do(forward,{wlan,mac,Sub_Mac},Sub_Packet#sub_packet{index=Packet_Index,ran_info=#wlan_spec{ap_ip = AP_ip,ac_ip = IP}}),%%#sub_packet{index=lists:last(P_Tuple#packet_tuple.context)}),
	{noreply,{running,IP,
		case Sub_Packet#sub_packet.prot of
		llc ->
			Counter#wlan80211c{data = Counter#wlan80211c.data + 1};
		i80211mgt ->
			Counter#wlan80211c{mgt = Counter#wlan80211c.mgt + 1};
		_ ->
			gen_event:notify(unknown_packet_evt,unable_to_handle,{i80211onlwapp,Packet_Index,{AP_ip,IP}}),
			Counter#wlan80211c{unknown = Counter#wlan80211c.unknown + 1}
		end}
	};	
handle_cast(_, State) ->
	{noreply,State}.
handle_info(_, State) ->
	{noreply,State}.
terminate(_, _) ->
	ok.
code_change(_, State, _) ->
	{ok,State}.	
	
parse80211frame(Packet) ->
	<<I80211_Header:26/binary,Payload/binary>> = Packet,
	case I80211_Header of
	<<_SubType:4,2:2,_Ver:2,_OFlags:6,2:2,_Duration:16,BSSID:6/binary,S_MAC:6/binary,D_MAC:6/binary,_Other/binary>> -> %% data frame to STA
		{D_MAC,#sub_packet{dir=down,prot=llc,packet=Payload}};
	<<_SubType:4,2:2,_Ver:2,_OFlags:6,1:2,_Duration:16,D_MAC:6/binary,BSSID:6/binary,S_MAC:6/binary,_Other/binary>> -> %% data frame to DS
		{S_MAC,#sub_packet{dir=up,prot=llc,packet=Payload}};
	<<SubType:4,0:2,_Ver:2,_OFlags:6,Dir:2,_Duration:16,D_MAC:6/binary,S_MAC:6/binary,BSSID:6/binary,_Other/binary>> -> %%
		case i80211mgt_analysis(SubType,Dir) of
		up ->
			{S_MAC,#sub_packet{dir=up,prot=i80211mgt,packet=Packet}};
		down ->
			{D_MAC,#sub_packet{dir=down,prot=i80211mgt,packet=Packet}};
		unknown ->
			{unknown,#sub_packet{dir=unknow,prot=i80211mgt,packet=Packet}} %% ignore
		end;
	_ ->
		{unknown,#sub_packet{dir=unknow,prot=unknow,packet=Packet}}
	end.
	
i80211mgt_analysis(0,_) ->
	up;
i80211mgt_analysis(1,_) ->
	down;
i80211mgt_analysis(2,_) ->
	up;
i80211mgt_analysis(3,_) ->
	down;
i80211mgt_analysis(4,_) ->
	up;
i80211mgt_analysis(5,_) ->
	down;
i80211mgt_analysis(10,2) ->
	up;
i80211mgt_analysis(10,3) ->
	down;	
i80211mgt_analysis(10,_) ->
	up;	
i80211mgt_analysis(11,2) ->
	up;
i80211mgt_analysis(11,3) ->
	down;	
i80211mgt_analysis(11,_) ->
	up;		
i80211mgt_analysis(_,_) ->
	unknown.


		
		
		
		